<template>
  <div class="app-container">
    <el-form
      v-show="showSearch"
      ref="queryForm"
      class="filter-search"
      :model="queryParams"
      :inline="true"
      label-width="68px"
    >
      <el-form-item label="菜单名称" prop="menuName">
        <el-input
          v-model="queryParams.menuName"
          placeholder="请输入菜单名称"
          clearable
          @keyup.enter="handleQuery"
        />
      </el-form-item>
      <el-form-item label="状态" prop="status">
        <el-select v-model="queryParams.status" placeholder="菜单状态" clearable @change="handleQuery">
          <el-option
            v-for="dict in $dict.normal_disable"
            :key="dict.value"
            :label="dict.label"
            :value="dict.value"
          />
        </el-select>
      </el-form-item>
      <el-form-item style="float: right;">
        <el-button type="primary" :icon="Search" @click="handleQuery">搜索</el-button>
        <el-button :icon="Refresh" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>
    <div class="content-box">
      <el-row :gutter="10" class="mb20">
        <el-col :span="1.5">
          <el-button
            v-has-perm="['permission:menu:add']"
            type="primary"
            plain
            :icon="Plus"
            @click="handleAdd"
          >新增
          </el-button>
        </el-col>
        <el-col :span="1.5">
          <el-button
            type="info"
            plain
            :icon="Sort"
            @click="toggleExpandAll"
          >展开/折叠
          </el-button>
        </el-col>
        <div style="flex: 1" />
        <right-toolbar v-model:show-search="showSearch" @query-table="getList" />
      </el-row>

      <el-scrollbar style="height: 66vh;">
        <el-table
          v-if="refreshTable"
          v-loading="loading"
          :data="menuList"
          row-key="id"
          :default-expand-all="isExpandAll"
          :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
        >
          <el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160" />
          <el-table-column prop="icon" label="图标" align="center" width="100">
            <template #default="scope">
              <svg-icon :icon-class="scope.row.icon" />
            </template>
          </el-table-column>
          <el-table-column prop="sort" label="排序" width="60" />
          <el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true" />
          <el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true" />
          <el-table-column prop="status" label="状态" width="80">
            <template #default="scope">
              <dict-tag :options="$dict.normal_disable" :value="scope.row.status" />
            </template>
          </el-table-column>
          <el-table-column label="创建时间" align="center" prop="createTime">
            <template #default="scope">
              <span>{{ parseTime(scope.row.createTime) }}</span>
            </template>
          </el-table-column>
          <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
            <template #default="scope">
              <el-button
                v-has-perm="['permission:menu:edit']"
                link
                :icon="Edit"
                style="color: #6bbd6e"
                @click="handleUpdate(scope.row)"
              >修改
              </el-button>
              <el-button
                v-has-perm="['permission:menu:add']"
                link
                :icon="Plus"
                style="color: #409eff"
                @click="handleAdd(scope.row)"
              >新增
              </el-button>
              <el-button
                v-has-perm="['permission:menu:add']"
                v-if="scope.row.menuType === 'C'"
                link
                :icon="CirclePlus"
                style="color: #f572b9"
                @click="dialogref.open(scope.row)"
              >生成
              </el-button>
              <el-button
                v-has-perm="['permission:menu:delete']"
                v-if="scope.row.children===undefined||scope.row.children.length===0"
                link
                :icon="Delete"
                style="color: #F56C6C"
                @click="handleDelete(scope.row)"
              >删除
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-scrollbar>
    </div>

    <el-dialog :title="title" v-model="open" width="50vw" append-to-body @close="cancel">
      <el-form ref="dialogFormRef" :model="form" :rules="rules" label-width="112px">
        <el-row>
          <el-col :span="24">
            <el-form-item label="上级菜单">
              <el-tree-select
                v-model="form.parentId"
                :data="menuOptions"
                :props="{ value: 'id', label: 'menuName', children: 'children' }"
                value-key="menuId"
                placeholder="选择上级菜单"
                check-strictly
              />
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="菜单类型" prop="menuType">
              <el-radio-group v-model="form.menuType">
                <el-radio value="M">目录</el-radio>
                <el-radio value="C">菜单</el-radio>
                <el-radio value="F">按钮</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="24 " v-if="form.menuType !== 'F'">
            <el-form-item label="菜单图标" prop="icon">
              <el-popover
                placement="bottom-start"
                :width="540"
                trigger="click"
                @show="iconSelectRef.reset()"
              >
                <icon-select ref="iconSelectRef" @selected="selected" />
                <template #reference>
                  <el-input v-model="form.icon" placeholder="点击选择图标" readonly>
                    <template #prefix>
                      <svg-icon
                        v-if="form.icon"
                        :icon-class="form.icon"
                        class="el-input__icon"
                        style="height: 32px;width: 16px;"
                      />
                      <el-icon v-else style="height: 32px;width: 16px;">
                        <search />
                      </el-icon>
                    </template>
                  </el-input>
                </template>
              </el-popover>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="菜单名称" prop="menuName">
              <el-input v-model="form.menuName" placeholder="请输入菜单名称" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="显示排序" prop="sort">
              <el-input-number v-model="form.sort" controls-position="right" :min="0" />
            </el-form-item>
          </el-col>
          <el-col v-if="form.menuType === 'C'" :span="24">
            <el-form-item prop="component">
              <template #label>
                <span style="font-weight: bolder">
                  <el-tooltip content="访问的组件路径，如：`server/home/index`，默认在`views`目录下" placement="top">
                    <el-icon><question-filled /></el-icon>
                  </el-tooltip>
                  组件路径
                </span>
              </template>
              <el-radio-group v-model="pathSelectModel" style="display: inline-block">
                <el-radio-button value="0">选择</el-radio-button>
                <el-radio-button value="1">输入</el-radio-button>
              </el-radio-group>
              <el-cascader
                v-if="pathSelectModel === '0'"
                v-model="curSelectPath"
                style="width: 470px; margin-left: 8px; display: inline-block"
                placeholder="请选择组件路径"
                :options="allPaths"
                :props="{expandTrigger: 'hover'}"
                @change="setSelectedPath"
              />
              <el-input
                v-if="pathSelectModel === '1'"
                v-model="form.component"
                style="width: 470px;  margin-left: 8px;"
                placeholder="请输入组件路径"
                @change="inputComponentChange"
              />
            </el-form-item>
          </el-col>
          <el-col v-if="form.menuType !== 'M'" :span="12">
            <el-form-item>
              <el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
              <template #label>
                <span>
                  <el-tooltip
                    content="控制器中定义的权限字符，如：@PreAuthorize(`@ss.hasPermi('permission:user:list')`)"
                    placement="top"
                  >
                    <el-icon><question-filled /></el-icon>
                  </el-tooltip>
                  权限字符
                </span>
              </template>
            </el-form-item>
          </el-col>
          <el-col v-if="form.menuType === 'C'" :span="12">
            <el-form-item>
              <el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
              <template #label>
                <span>
                  <el-tooltip
                    content="访问路由的默认传递参数，如：`{&quot;id&quot;: 1, &quot;name&quot;: &quot;ry&quot;}`"
                    placement="top"
                  >
                    <el-icon><question-filled /></el-icon>
                  </el-tooltip>
                  路由参数
                </span>
              </template>
            </el-form-item>
          </el-col>
          <el-col v-if="form.menuType !== 'F'" :span="12">
            <el-form-item>
              <template #label>
                <span>
                  <el-tooltip content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
                    <el-icon><question-filled /></el-icon>
                  </el-tooltip>
                  是否外链
                </span>
              </template>
              <el-radio-group v-model="form.frame">
                <el-radio :value="true">是</el-radio>
                <el-radio :value="false">否</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col v-if="form.menuType !== 'F'" :span="12">
            <el-form-item prop="path">
              <template #label>
                <span>
                  <el-tooltip
                    content="访问的路由地址，如：`user`，如外网地址需内链访问则以`http(s)://`开头"
                    placement="top"
                  >
                    <el-icon><question-filled /></el-icon>
                  </el-tooltip>
                  路由地址
                </span>
              </template>
              <el-input v-model="form.path" placeholder="请输入路由地址" />
            </el-form-item>
          </el-col>
          <el-col v-if="form.menuType === 'C'" :span="12">
            <el-form-item>
              <template #label>
                <span>
                  <el-tooltip content="选择是则会被`keep-alive`缓存，需要匹配组件的`name`和地址保持一致" placement="top">
                    <el-icon><question-filled /></el-icon>
                  </el-tooltip>
                  是否缓存
                </span>
              </template>
              <el-radio-group v-model="form.cache">
                <el-radio :value="true">缓存</el-radio>
                <el-radio :value="false">不缓存</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col v-if="form.menuType !== 'F'" :span="12">
            <el-form-item>
              <template #label>
                <span>
                  <el-tooltip content="选择隐藏则路由将不会出现在侧边栏，但仍然可以访问" placement="top">
                    <el-icon><question-filled /></el-icon>
                  </el-tooltip>
                  显示状态
                </span>
              </template>
              <el-radio-group v-model="form.visible">
                <el-radio
                  v-for="dict in $dict.show_hide"
                  :key="dict.value"
                  :value="dict.value"
                >{{ dict.label }}
                </el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col v-if="form.menuType !== 'F'" :span="12">
            <el-form-item>
              <template #label>
                <span>
                  <el-tooltip content="选择停用则路由将不会出现在侧边栏，也不能被访问" placement="top">
                    <el-icon><question-filled /></el-icon>
                  </el-tooltip>
                  菜单状态
                </span>
              </template>
              <el-radio-group v-model="form.status">
                <el-radio
                  v-for="dict in $dict.normal_disable"
                  :key="dict.value"
                  :value="dict.value"
                >{{ dict.label }}
                </el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">确 定</el-button>
          <el-button @click="cancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>

    <GenBtnRuleDialog ref="dialogref" @success="getList" />
  </div>
</template>

<script setup>
import { CirclePlus, Delete, Edit, Plus, QuestionFilled, Refresh, Search, Sort } from '@element-plus/icons-vue'
import { handleTree, parseTime } from "@/utils/index.js"
import GenBtnRuleDialog from "@/views/common/permission/menu/genBtnRuleDialog.vue"
import getAllPagePath from "@/utils/getAllPagePath.js"

const dialogref = ref(null)
// 遮罩层
const loading = ref(false)
// 显示搜索条件
const showSearch = ref(true)
// 菜单表格树数据
const menuList = ref([])
// 表单参数
const form = ref({})
// 菜单树选项
const menuOptions = ref([])
// 是否显示弹出层
const open = ref(false)
// 弹出层标题
const title = ref()
// 重新渲染表格状态
const refreshTable = ref(true)
// 是否展开，默认全部折叠
const isExpandAll = ref(false)
const curSelectPath = ref('')
const iconSelectRef = ref(null)
const pathSelectModel = ref('0')

const rules = {
  menuName: [
    {required: true, message: '菜单名称不能为空', trigger: 'blur'}
  ],
  sort: [
    {required: true, message: '菜单顺序不能为空', trigger: 'blur'}
  ],
  path: [
    {required: true, message: '路由地址不能为空', trigger: 'blur'}
  ]
}


// 查询参数
const queryParams = reactive({
  menuName: undefined,
  visible: undefined
})

function getList() {
  loading.value = true
  $xl.apis.getMenus({
    params: queryParams
  }).then(res => {
    menuList.value = handleTree(res.data, 'id')
    loading.value = false
  }).catch(err => {
    loading.value = false
    $xl.modal.msgError(err)
  })
}

function handleQuery() {
  getList()
}

const proxy = getCurrentInstance()

function resetQuery() {
  proxy.refs.queryForm.resetFields()
  handleQuery()
}

function handleAdd(row) {
  reset()
  getTreeSelect()
  if (row != null && row.id) {
    form.value.parentId = row.id
    nextTick(() => {
      if (row.menuType === 'M') form.value.menuType = 'C'
      else if (row.menuType === 'C') form.value.menuType = 'F'
    })
  } else {
    form.value.parentId = 0
  }
  open.value = true
  title.value = '新增菜单'
}

function reset() {
  form.value = {
    id: undefined,
    parentId: 0,
    menuName: undefined,
    icon: undefined,
    menuType: "M",
    sort: 0,
    path: '',
    orderNum: 0,
    frame: false,
    cache: false,
    visible: '0',
    status: '0'
  }
}

/** 查询菜单下拉树结构 */
function getTreeSelect() {
  menuOptions.value = []
  const menu = {id: 0, menuName: '主类目', children: []}
  menu.children = menuList.value
  menuOptions.value.push(menu)
}


function toggleExpandAll() {
  refreshTable.value = false
  isExpandAll.value = !isExpandAll.value
  nextTick(() => {
    refreshTable.value = true
  })
}

/** 修改按钮操作 */
function handleUpdate(row) {
  reset()
  getTreeSelect()
  $xl.apis.getMenu({
    jointUrl: '/' + row.id
  }).then(res => {
    delete res.data['children']
    form.value = res.data
    if (form.value.component) curSelectPath.value = form.value.component.split('/')
    open.value = true
    title.value = '修改菜单'
  })
}

/** 删除按钮操作 */
function handleDelete(row) {
  $xl.modal.confirm('是否确认删除名称为"' + row.menuName + '"的数据项？').then(() => {
    $xl.apis.deleteMenu({
      jointUrl: '/' + row.id
    }).then(() => {
      getList()
      $xl.modal.msgSuccess('删除成功')
    }).catch(err => $xl.modal.msgError(err))
  }).catch(() => {
  })
}

function selected(name) {
  form.value.icon = name
}

function setSelectedPath(value) {
  let path
  value.forEach(item => {
    if (path) {
      path = path + '/' + item
    } else {
      path = item
    }
  })
  form.value.component = path
  const linkPath = path.split('/').slice(-1).toString()
  form.value.path = linkPath.charAt(0).toLowerCase() + linkPath.slice(1)
}

function inputComponentChange() {
  curSelectPath.value = form.value.component.split('/')
}

// 取消按钮
function cancel() {
  open.value = false
  reset()
}

function submitForm() {
  if (form.value.menuType === 'M') {
    if (form.value.path.startsWith('/')) {
      form.value.path = form.value.path.substring(1)
    }
  }
  proxy.refs.dialogFormRef.validate(valid => {
    if (valid) {
      if (form.value.id !== undefined) {
        $xl.apis.updateMenu({
          params: form.value
        }).then(() => {
          $xl.modal.msgSuccess('修改成功')
          open.value = false
          getList()
        }).catch(err => {
          $xl.modal.msgError(err)
        })
      } else {
        $xl.apis.saveMenu({
          params: form.value
        }).then(() => {
          $xl.modal.msgSuccess('新增成功')
          open.value = false
          getList()
        }).catch(err => {
          $xl.modal.msgError(err)
        })
      }
    }
  })
}

const allPaths = [convertPathToNestedStructure(getAllPagePath[0]), convertPathToNestedStructure(getAllPagePath[1])]

function convertPathToNestedStructure(paths) {
  if (!Array.isArray(paths) || paths.length === 0) {
    return {value: '', label: '', children: []} // 返回一个空结构
  }
  const root = {value: '', label: '', children: []}
  let path
  for (path of paths) {
    const parts = path.split('/')
    parts.shift() // 删除第一个空元素
    let currentLevel = root
    for (const part of parts) {
      const existingPath = currentLevel.children.find(child => child.value === part)
      if (existingPath) {
        currentLevel = existingPath
      } else {
        const newItem = {value: part, label: part, children: []}
        currentLevel.children.push(newItem)
        currentLevel = newItem
      }
    }
  }
  clearEmptyChildren(root)
  return root.children[0] // 返回 "server" 下的结构
}

function clearEmptyChildren(node) {
  if (node.children.length === 0) {
    delete node.children
  } else {
    for (const child of node.children) {
      clearEmptyChildren(child)
    }
  }
}

onMounted(() => {
  getList()
})
</script>

<style lang="scss" scoped>

:deep(.el-table__row--level-1) {
  background-color: #f9f9f9 !important;

  &:hover {
    background-color: #F3F7FE !important;
  }
}

:deep(.el-table__row--level-2) {
  background-color: #f9f9f9 !important;

  &:hover {
    background-color: #F3F7FE !important;
  }
}
</style>
